home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / apps / gmemusage / process.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  21KB  |  840 lines

  1. /*
  2.  * process.c
  3.  *
  4.  * Code to collect information about memory usage in the system
  5.  *
  6.  * Copyright 1994, Silicon Graphics, Inc.
  7.  * All Rights Reserved.
  8.  *
  9.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  10.  * the contents of this file may not be disclosed to third parties, copied or
  11.  * duplicated in any form, in whole or in part, without the prior written
  12.  * permission of Silicon Graphics, Inc.
  13.  *
  14.  * RESTRICTED RIGHTS LEGEND:
  15.  * Use, duplication or disclosure by the Government is subject to restrictions
  16.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  17.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  18.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  19.  * rights reserved under the Copyright Laws of the United States.
  20.  */
  21.  
  22. #define _KMEMUSER
  23. #include <sys/types.h>
  24. #include <sys/procfs.h>
  25. #include <sys/param.h>
  26. #include <sys/sysmp.h>
  27. #include <sys/sysinfo.h>
  28. #include <sys/sysmacros.h>
  29. #include <sys/sbd.h>
  30. #include <sys/pfdat.h>
  31. #include <sys/proc.h>
  32.  
  33. #include <dirent.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <unistd.h>
  37. #include <fcntl.h>
  38. #include <errno.h>
  39. #include <stdio.h>
  40. #include <ctype.h>
  41.  
  42. #include "process.h"
  43. #include "inode.h"
  44.  
  45. #define PROCDIR "/proc"
  46. #define MAXMAPS        256
  47.  
  48.  
  49. /*
  50.  * dirp is for opening /proc
  51.  */
  52. static DIR *dirp = NULL;
  53. static unsigned long kpstart, ktext, ketext, kend, kpbase, kpfdat;
  54. static unsigned long kpagesize;
  55.  
  56. static int pgsize;      /* page size in 1000 of bytes (ie. 4, 16, etc...) */
  57.  
  58. /*
  59.  *  void
  60.  *  KernelInfo()
  61.  *
  62.  *  Description:
  63.  *      Initialize a few constant global kernel variables
  64.  */
  65. void
  66. KernelInfo(void)
  67. {
  68.     register int fd;
  69.  
  70.     /* Only do once */
  71.     if (!kend) {
  72.         /* Get some info from sysmp() */
  73.         if ((kpstart = sysmp(MP_KERNADDR, MPKA_PSTART)) == -1)
  74.             perror("sysmp(MP_KERNADDR, MPKA_PSTART)");
  75.         kpstart = PHYS_TO_K0(kpstart);
  76.         if ((ktext = sysmp(MP_KERNADDR, MPKA_TEXT)) == -1)
  77.             perror("sysmp(MP_KERNADDR, MPKA_TEXT)");
  78.         if ((ketext = sysmp(MP_KERNADDR, MPKA_ETEXT)) == -1)
  79.             perror("sysmp(MP_KERNADDR, MPKA_ETEXT)");
  80.         if ((kend = sysmp(MP_KERNADDR, MPKA_END)) == -1)
  81.             perror("sysmp(MP_KERNADDR, MPKA_END)");
  82.         if ((kpfdat = sysmp(MP_KERNADDR, MPKA_PFDAT)) == -1)
  83.             perror("sysmp(MP_KERNADDR, MPKA_PFDAT)");
  84.         if ((kpbase = sysmp(MP_KERNADDR, MPKA_KPBASE)) == -1)
  85.             perror("sysmp(MP_KERNADDR, MPKA_KPBASE)");
  86.         
  87.         /* Read some stuff from /dev/kmem */
  88.         if (fd = open("/dev/kmem", 0)) {
  89.             /* Get value of KPBASE */
  90.             if (lseek(fd, kpbase, SEEK_SET) == -1)
  91.                 perror("lseek");
  92.             if (read(fd, (caddr_t)&kpbase, sizeof kpbase) < 0)
  93.                 perror("read");
  94.             kpfdat += btoct(kpbase) * sizeof (pfd_t);
  95.             kpbase = PHYS_TO_K0(kpbase);
  96.  
  97.             close(fd);
  98.         }
  99.     }
  100. }
  101.  
  102. /*
  103.  *  static PROGRAM *
  104.  *  AddElem(PROGRAM *head, char *progName, char *mapName, char *mapType,
  105.  *          long privSize, long weightSize, long resSize, long size,
  106.  *          pid_t pid, int markNProc)
  107.  *
  108.  *  Description:
  109.  *      Add an element to our program list.
  110.  *
  111.  *  Parameters:
  112.  *      head         The list to add this element to
  113.  *      progName     Name of program to add
  114.  *    privSize     Size of private pages
  115.  *      weightSize   Weighted memusage size
  116.  *      resSize         resident size of program to add
  117.  *      size         total size of program to add
  118.  *      pid         process id of program to add
  119.  *      markNProc    1 if we care about keeping nProc up to date
  120.  *
  121.  *  Returns:
  122.  *      A new list (the element being added may go at the beginning)
  123.  */
  124.  
  125. static PROGRAM *
  126. AddElem(PROGRAM *head, char *progName, char *mapName, char *mapType,
  127.     long privSize, long weightSize, long resSize,
  128.     long size, pid_t pid, int markNProc)
  129. {
  130.     PROGRAM *elem, *prev, *pidPlace;
  131.     int cmp;
  132.  
  133.     elem = head;
  134.     prev = NULL;
  135.     pidPlace = NULL;
  136.  
  137.     /*
  138.      * Look for another copy of the same program already running
  139.      */
  140.     while (elem && (cmp = strcmp(progName, elem->progName)) != 0) {
  141.     /*
  142.      * Remember where the program should go (we sort by pid) in
  143.      * case this is the first of its kind that we've found
  144.      */
  145.     if (pid < elem->pid && !pidPlace) {
  146.         pidPlace = prev;
  147.     }
  148.     prev = elem;
  149.     elem = elem->next;
  150.     }
  151.     
  152.     if (elem && cmp == 0) {
  153.     /*
  154.      * Another copy is running; just add the new one's stats to
  155.      * the old one
  156.      */
  157.     elem->privSize += privSize;
  158.     elem->weightSize += weightSize;
  159.     elem->resSize += resSize;
  160.     elem->size += size;
  161.     if (markNProc) {
  162.         elem->nProc++;
  163.     }
  164.     } else {
  165.     /*
  166.      * A new program is encountered.  Allocate a new element, and
  167.      * insert it into the list.
  168.      */
  169.     elem = malloc(sizeof *elem);
  170.  
  171.     /*
  172.      * progName and mapName get strduped because the point to
  173.      * things like prinfo structs that change.  mapType points to
  174.      * static storage that does not change.  Be very careful if
  175.      * you change this, because FreeUsage (in this file) knows
  176.      * about this, AND SO DOES DrawSetup (in draw.c)!!!
  177.      */
  178.     elem->progName = strdup(progName);
  179.     elem->mapName = mapName ? strdup(mapName) : NULL;
  180.     elem->mapType = mapType; /* Don't need to dup this; it points */
  181.                  /* to static storage that won't change */
  182.     elem->privSize = privSize;
  183.     elem->weightSize = weightSize;
  184.     elem->resSize = resSize;
  185.     elem->size = size;
  186.     elem->pid = pid;
  187.     elem->nProc = 1;
  188.     elem->print = 1;
  189.     
  190.     if (!prev) {
  191.         elem->prev = NULL;
  192.         elem->next = head;
  193.         head = elem;
  194.     } else {
  195.         if (pidPlace) {
  196.         prev = pidPlace;
  197.         }
  198.         elem->next = prev->next;
  199.         elem->prev = prev;
  200.         prev->next = elem;
  201.         if (elem->next) {
  202.         elem->next->prev = elem;
  203.         }
  204.     }
  205.     }
  206.     return head;
  207. }
  208.  
  209. /*
  210.  *  static PROGRAM *
  211.  *  SortList(PROGRAM *head, int flag)
  212.  *
  213.  *  Description:
  214.  *    Sort the element list by physical size (largest first)
  215.  *
  216.  *  Parameters:
  217.  *      head         Start of the double linked list of elements
  218.  *
  219.  *  Returns:
  220.  *    New head of the list
  221.  */
  222.  
  223. static PROGRAM *
  224. SortList(PROGRAM *head, int flag)
  225. {
  226.     PROGRAM *new = NULL, *prev, *walk, *next, *scan;
  227.  
  228.     /* Walk the original list */
  229.     for (walk = head; walk != NULL; walk = next) {
  230.         /* Correct weightSize values */
  231.         if (flag != 0) {
  232.             walk->weightSize += MA_WSIZE_FRAC - 1;
  233.             walk->weightSize /= MA_WSIZE_FRAC;
  234.         }
  235.  
  236.         /* Get it now, will be rewritten below */
  237.         next = walk->next;
  238.  
  239.         /* No sort, just scale */
  240.         if (flag < 0) {
  241.             new = head;
  242.             continue;
  243.         }
  244.  
  245.         /* Put into new sorted list */
  246.         for (prev = NULL, scan = new; scan != NULL;
  247.              scan = scan->next) {
  248.             if (walk->weightSize > scan->weightSize)
  249.                 break;
  250.             prev = scan;
  251.         }
  252.         
  253.         /* Insert into new list before current element */
  254.         if (scan) {
  255.             walk->next = scan;
  256.             walk->prev = scan->prev;
  257.             scan->prev = walk;
  258.             if (prev)
  259.                 prev->next = walk;
  260.             else
  261.                 new = walk;
  262.         } else if (new) {
  263.             walk->prev = prev;
  264.             prev->next = walk;
  265.             walk->next = NULL;
  266.         } else {
  267.             new = walk;
  268.             walk->prev = NULL;
  269.             walk->next = NULL;
  270.         }
  271.     }
  272.     
  273.     return new;
  274. }
  275.  
  276. /*
  277.  * Indentify RLD bss extents
  278.  */
  279. isrldbss(struct prmap_sgi *map)
  280. {
  281.     if (((unsigned)map->pr_vaddr >= 0x0fbc0000) &&
  282.         ((unsigned)map->pr_vaddr < 0x0fc40000))
  283.         return 1;
  284.     return 0;
  285. }
  286.  
  287. /*
  288.  * Indentify /dev/zero
  289.  */
  290. isdevzero(struct prmap_sgi *map)
  291. {
  292.     static dev_t zdev;
  293.     static ino_t zino;
  294.  
  295.     /* Lookup /dev/zero */
  296.     if (!zdev) {
  297.         FindInode("zero", &zdev, &zino);
  298.     }
  299.  
  300.     /* Match? */
  301.     if (map->pr_dev == zdev && map->pr_ino == zino)
  302.         return 1;
  303.     return 0;
  304. }
  305.  
  306. /*
  307.  *  char *
  308.  *  MapFlags(prmap_sgi_t *map)
  309.  *
  310.  *  Description:
  311.  *      Translate the flags for a region into a meaningful word that
  312.  *      describes what type of region it is
  313.  *
  314.  *  Parameters:
  315.  *      map  region pointer
  316.  *
  317.  *  Returns:
  318.  *      string describing the type of region
  319.  */
  320.  
  321. char *
  322. MapFlags(prmap_sgi_t *map)
  323. {
  324.     if (map->pr_mflags & MA_PHYS) {
  325.     return "Physical Device";
  326.     } else if (map->pr_mflags & MA_STACK) {
  327.     return "Stack";
  328.     } else if (map->pr_mflags & MA_BREAK) {
  329.     return "Break";
  330.     } else if (map->pr_mflags & MA_EXEC) {
  331.     return "Text";
  332.     } else if (map->pr_mflags & MA_COW) {
  333.     return "Data";
  334.     } else if (map->pr_mflags & MA_SHMEM) {
  335.     return "Shmem";
  336.     } else if ((map->pr_mflags & (MA_READ | MA_WRITE)) ==
  337.            (MA_READ | MA_WRITE)) {
  338.     return "RW";
  339.     } else if (map->pr_mflags & MA_READ) {
  340.     return "RO";
  341.     }
  342.     return "Other";
  343. }
  344.  
  345. /*
  346.  *  int
  347.  *  PteAccounting(prmap_sgi_t *maps, int nmaps)
  348.  *
  349.  *  Description:
  350.  *    Try and figure out how many page tables are in core
  351.  *
  352.  *  Parameters:
  353.  *      maps  region pointer
  354.  *    nmaps number of maps in region list
  355.  */
  356. PteAccounting(prmap_sgi_t *maps, int nmaps)
  357. {
  358.     unsigned pteblksize = (kpagesize / sizeof (caddr_t)) * kpagesize;
  359.     prmap_sgi_t *map;
  360.     long segno, refcnt, lrefcnt = 0, space = 0;
  361.     caddr_t vaddr, vend;
  362.     int i, last = -1;
  363.  
  364.     /* Search all the segments */
  365.     for (map = maps, i = 0; i < nmaps; ++map, ++i) {
  366.         /* Skip empty ones */
  367.         if (map->pr_vsize == 0)
  368.             continue;
  369.  
  370.         /* Walk segment one segment at a time (XXX fix me) */
  371.         vaddr = map->pr_vaddr; 
  372.         vend = map->pr_vaddr + map->pr_size; 
  373.         refcnt = map->pr_mflags >> MA_REFCNT_SHIFT;
  374.         while (vaddr < vend) {
  375.             /* If not same as last time & incore, then bill me */
  376.             segno = (long)vaddr / pteblksize;
  377.             if (last == -1)
  378.                 last = segno;
  379.             if (last != segno) {
  380.                 space += kpagesize / lrefcnt;
  381.                 last = segno;
  382.                 lrefcnt = 0;
  383.             }
  384.             vaddr += pteblksize;
  385.             if (!lrefcnt || (refcnt < lrefcnt)) {
  386.                 lrefcnt = refcnt;
  387.             }
  388.         }
  389.     }
  390.     if (lrefcnt) {
  391.         space += kpagesize / lrefcnt;
  392.     }
  393.  
  394.     return space / 1024;
  395. }
  396.  
  397. /*
  398.  * Indentify PROGRAM text extent
  399.  */
  400. static int
  401. isprgtxt(struct prmap_sgi *map)
  402. {
  403.     if ((map->pr_mflags & (MA_EXEC|MA_PRIMARY)) == (MA_PRIMARY|MA_EXEC))
  404.         return 1;
  405.     return 0;
  406. }
  407.  
  408. /*
  409.  * Indentify RLD text extent
  410.  */
  411. static int
  412. isrldtxt(struct prmap_sgi *map)
  413. {
  414.     if ((unsigned)map->pr_vaddr == 0x0fb60000)
  415.         return 1;
  416.     return 0;
  417. }
  418.  
  419. /*
  420.  *  static void OpenProcDir(void)
  421.  *
  422.  *  Description:
  423.  *    Open /proc if it's not open, and rewind.  dirp is a global
  424.  *    variable.
  425.  */
  426.  
  427. static void OpenProcDir(void)
  428. {
  429.     /* Get system page size */
  430.     if (!kpagesize)
  431.     kpagesize = getpagesize();
  432.  
  433.     pgsize = kpagesize/1024;
  434.  
  435.     if (!dirp) {
  436.     if ((dirp = opendir(PROCDIR)) == NULL) {
  437.         perror(PROCDIR);
  438.         exit(1);
  439.     }
  440.     }
  441.  
  442.     rewinddir(dirp);
  443. }     
  444.  
  445. /*
  446.  *  void GetObjInfo(char *objName, PROGRAM **all, PROGRAM **objp)
  447.  *
  448.  *  Description:
  449.  *      Get physical memory usage information for all mapped objects
  450.  *      in the system.
  451.  *
  452.  *  Parameters:
  453.  *      objName    name of object to get detailed information for
  454.  *      all     gets usage for all objectss
  455.  *      objp    gets usage for a specific object
  456.  */
  457.  
  458. void GetObjInfo(char *objName, PROGRAM **all, PROGRAM **objp)
  459. {
  460.     struct dirent *dent;
  461.     char procFile[MAXPATHLEN];
  462.     int status, fd, nmaps, i, pid = 1, ppid = 1, mino;
  463.     register struct prmap_sgi *map, *amap, *rmap, *bmap;
  464.     struct prmap_sgi maps[MAXMAPS];
  465.     prmap_sgi_arg_t maparg;
  466.     PROGRAM *list = NULL;
  467.     PROGRAM *plist = NULL;
  468.     unsigned long refCount;
  469.     double rss;
  470.     char *mname, *flagName;
  471.     struct prpsinfo info;
  472.     long uspace = 0, ptespace = 0, mem;
  473.  
  474.     maparg.pr_vaddr = (caddr_t)maps;
  475.     maparg.pr_size = sizeof maps;
  476.  
  477.     OpenProcDir();
  478.  
  479.     while ((dent = readdir(dirp)) != NULL) {
  480.     if (!isdigit(dent->d_name[0]))
  481.          continue;
  482.  
  483.     sprintf(procFile, "%s/%s", PROCDIR, dent->d_name);
  484.  
  485.     status = (fd = open(procFile, O_RDONLY)) != -1
  486.         && ioctl(fd, PIOCPSINFO, &info) != -1
  487.         && (nmaps = ioctl(fd, PIOCMAP_SGI, &maparg)) != -1;
  488.  
  489.     close(fd);
  490.  
  491.     if (!status) {
  492.         continue;
  493.     }
  494.  
  495.     /* Figure out if U-area is in core and charge process for it */
  496.     uspace += (info.pr_flag & SULOAD) ? (USIZE * kpagesize / 1024) : 0;
  497.  
  498.     /* Try and figure out how many page tables are resident in memory */
  499.     ptespace += PteAccounting(maps, nmaps);
  500.  
  501.     amap = NULL;
  502.     rmap = NULL;
  503.  
  504.     /* Search regions to find app segment & rld segment */
  505.     for (map = maps, i = nmaps; i-- > 0; ++map) {
  506.         /* Hack for app region */
  507.         if (!amap && isprgtxt(map)) {
  508.         amap = map;
  509.         }
  510.  
  511.         /* Remember primary BRK region */
  512.         if ((map->pr_mflags & (MA_PRIMARY|MA_BREAK)) ==
  513.                   (MA_PRIMARY|MA_BREAK)) {
  514.         bmap = map;
  515.         }
  516.         
  517.         /* Remember RLD region */
  518.         if (!rmap && isrldtxt(map)) {
  519.         rmap = map;
  520.         }
  521.     }
  522.     
  523.     /* Scan the table */
  524.     for (map = maps, i = nmaps; i-- > 0; ++map) {
  525.         if (map->pr_mflags & MA_PHYS) {
  526.         continue;
  527.         }
  528.  
  529.         /* Try and bill /dev/zero regions to real owners */
  530.         if (isdevzero(map)) {
  531.             /* Hack for rld's /dev/zero regions */
  532.         if (rmap && isrldbss(map)) {
  533.             map->pr_dev = rmap->pr_dev;
  534.             map->pr_ino = rmap->pr_ino;
  535.             map->pr_mflags |= MA_BREAK;
  536.         }
  537.         /* Otherwise bill to apps primary break region */
  538.         else if (bmap) {
  539.             map->pr_dev = bmap->pr_dev;
  540.             map->pr_ino = bmap->pr_ino;
  541.             map->pr_mflags |= MA_BREAK;
  542.         }
  543.         } else if (amap && ((map->pr_mflags & MA_STACK) ||
  544.                 (map->pr_mflags & MA_BREAK))) {
  545.         map->pr_dev = amap->pr_dev;
  546.         map->pr_ino = amap->pr_ino;
  547.         }
  548.  
  549.         if (map->pr_dev == amap->pr_dev && map->pr_ino == amap->pr_ino) {
  550.         mname = info.pr_fname;
  551.         } else {
  552.         mname = map->pr_ino ?
  553.             InodeLookup(map->pr_dev, map->pr_ino) : NULL;
  554.         }
  555.  
  556.         flagName = MapFlags(map);
  557.         refCount = map->pr_mflags >> MA_REFCNT_SHIFT;
  558.         rss = (double)map->pr_wsize;
  559.         rss *= pgsize;                /* use 1KB resolution */
  560.         rss /= (double)refCount;
  561.         list = AddElem(list, mname ? mname : flagName,
  562.                mname, flagName,
  563.                (map->pr_psize * pgsize) / refCount, rss,
  564.                0, 0, pid++, 0);
  565.         if (objName && mname && strcmp(objName, mname) == 0) {
  566.             plist = AddElem(plist, flagName, mname, flagName,
  567.                (map->pr_psize * pgsize) / refCount, rss,
  568.                0, 0, ppid++, 0);
  569.         }
  570.     }
  571.     }
  572.     list = SortList(list, 1);
  573.     if (plist) plist = SortList(plist, -1);
  574.     mem = uspace + ptespace;
  575.     list = AddElem(list, "U areas & PTEs", "U areas & PTES", IRIX,
  576.            mem, mem, 0, 0,
  577.            pid++, 0);
  578.     *all = list;
  579.     *objp = plist;
  580. }
  581.  
  582. /*
  583.  *  void
  584.  *  GetProcInfo(char *procName, PROGRAM **all, PROGRAM **proc)
  585.  *
  586.  *  Description:
  587.  *      Get memory usage information for all processes in the system.
  588.  *      In addition, collect detailed information for procName if it
  589.  *      is non-NULL.
  590.  *
  591.  *  Parameters:
  592.  *      procName  name of program to get detailed information for
  593.  *      all       gets usage for all processes
  594.  *      proc      gets usage for a specific process
  595.  */
  596.  
  597. void
  598. GetProcInfo(char *procName, PROGRAM **all, PROGRAM **proc)
  599. {
  600.     struct dirent *dent;
  601.     char procFile[MAXPATHLEN];
  602.     int fd, i;
  603.     struct prpsinfo info;
  604.     register prmap_sgi_t *map, *amap;
  605.     prmap_sgi_t maps[MAXMAPS];
  606.     prmap_sgi_arg_t maparg;
  607.     unsigned nmaps;
  608.     PROGRAM *list = NULL;
  609.     PROGRAM *plist = NULL;
  610.     char mapObjName[MAXPATHLEN + 20], *mname, *flagName;
  611.     int status;
  612.     struct rminfo rminfo;
  613.     struct minfo minfo;
  614.     long userTotal, pteTotal, uspace, ptespace, wrss, kmem, mem, privSize;
  615.     long weighted, refCount;
  616.  
  617.     maparg.pr_vaddr = (caddr_t)maps;
  618.     maparg.pr_size = sizeof maps;
  619.  
  620.     OpenProcDir();
  621.  
  622.     userTotal = pteTotal = 0;
  623.     while ((dent = readdir(dirp)) != NULL) {
  624.     if (!isdigit(dent->d_name[0]))
  625.          continue;
  626.  
  627.     sprintf(procFile, "%s/%s", PROCDIR, dent->d_name);
  628.  
  629.     status = (fd = open(procFile, O_RDONLY)) != -1
  630.         && ioctl(fd, PIOCPSINFO, &info) != -1
  631.         && (nmaps = ioctl(fd, PIOCMAP_SGI, &maparg)) != -1;
  632.  
  633.     close(fd);
  634.  
  635.     if (!status) {
  636.         continue;
  637.     }
  638.  
  639. #define pr_rss pr_fill[1]
  640.     wrss = 0;
  641.     privSize = 0;
  642.     /* Compute weighted rss from valid and usage counts */
  643.     for (map = maps, i = nmaps; i-- > 0; ++map) {
  644.         if ((map->pr_mflags & MA_PHYS) == 0) {
  645.         refCount = map->pr_mflags >> MA_REFCNT_SHIFT;
  646.         weighted = map->pr_wsize;
  647.         weighted *= pgsize;        /* use 1KB resolution */
  648.         weighted /= MA_WSIZE_FRAC;
  649.         weighted /= refCount;
  650.         map->pr_rss = (long)weighted;
  651.         wrss += weighted;
  652.         if ((map->pr_mflags & MA_SHMEM) == 0) {
  653.             privSize += (map->pr_psize * pgsize) / refCount;
  654.         }
  655.         } else {
  656.         map->pr_rss = 0;
  657.         }
  658.     }
  659.     userTotal += wrss;
  660.  
  661.     /* Figure out if U-area is in core and charge process for it */
  662.     uspace = (info.pr_flag & SULOAD) ? (USIZE * kpagesize / 1024) : 0;
  663.     userTotal += uspace;
  664.     privSize += uspace;
  665.  
  666.     /* Try and figure out how many page tables are resident in memory */
  667.     ptespace = PteAccounting(maps, nmaps);
  668.     pteTotal += ptespace;
  669.     privSize += ptespace;
  670.  
  671.     list = AddElem(list, info.pr_fname, NULL, NULL, privSize,
  672.                (long)wrss + uspace + ptespace,
  673.                info.pr_rssize * pgsize + uspace + ptespace,
  674.                info.pr_size * pgsize, info.pr_pid, 1);
  675.  
  676.     if (procName && strcmp(procName, info.pr_fname) == 0) {
  677.         amap = 0;
  678.         /*
  679.           * Find program text region, so we can get good names for
  680.          * the regions associated with each executable file even
  681.          * if that file isn't in our inode map.
  682.          */
  683.         for (map = maps, i = nmaps; i-- > 0; ++map) {
  684.         if (isprgtxt(map)) {
  685.             amap = map;
  686.             break;
  687.         }
  688.         }
  689.         
  690.         /* List all the address space segments in virtual order */
  691.         for (map = maps, i = nmaps; i-- > 0; ++map) {
  692.         if (isdevzero(map) && isrldbss(map)) {
  693.             mname = "rld";
  694.             map->pr_mflags |= MA_BREAK;
  695.         } else if ((map->pr_mflags & MA_STACK) ||
  696.                (map->pr_mflags & MA_BREAK) ||
  697.                (map->pr_dev == amap->pr_dev && map->pr_ino ==
  698.                 amap->pr_ino)) {
  699.             mname = procName;
  700.         } else {
  701.             mname = map->pr_ino ?
  702.             InodeLookup(map->pr_dev, map->pr_ino) : NULL;
  703.         }
  704.         flagName = MapFlags(map);
  705.         if (mname) {
  706.             sprintf(mapObjName, "%s (%s)", flagName, mname);
  707.             if (strlen(mapObjName) > 15) {
  708.             mapObjName[15] = ')';
  709.             mapObjName[16] = '\0';
  710.             }
  711.         }
  712.         refCount = map->pr_mflags >> MA_REFCNT_SHIFT;
  713.         plist = AddElem(plist, mname ? mapObjName : flagName,
  714.                 mname, flagName,
  715.                 ((map->pr_mflags & MA_PHYS) ||
  716.                  (map->pr_mflags & MA_SHMEM)) ?
  717.                 0 : (map->pr_psize * pgsize) / refCount,
  718.                 map->pr_rss,
  719.                 (map->pr_vsize * pgsize) / refCount,
  720.                 (map->pr_size + 1023) / 1024, nmaps - i, 0);
  721.         }
  722.  
  723.         /* Add U area & PTE space at the bottom */
  724.         mem = uspace + ptespace;
  725.         plist = AddElem(plist, "U area & PTEs", "U area & PTEs",
  726.                 IRIX, mem, mem, mem, mem, nmaps+1, 0);
  727.     }
  728.     }
  729.  
  730.     /*
  731.      * Special case if procName is "Irix".  We get info from the sysmp
  732.      * call.
  733.      */
  734.     if (procName && strcmp(procName, IRIX) == 0) {
  735.     KernelInfo();
  736.     if (sysmp(MP_SAGET, MPSA_RMINFO, &rminfo, sizeof rminfo) == -1
  737.         ||sysmp(MP_SAGET, MPSA_MINFO, &minfo, sizeof minfo) == -1) {
  738.         perror("sysmp");
  739.     } else {
  740.         i = 0;
  741.         kmem = (rminfo.physmem - rminfo.availrmem) * pgsize;
  742.         kmem -= pteTotal;
  743.         mem = (rminfo.physmem - rminfo.freemem) * pgsize 
  744.         - (userTotal + kmem + pteTotal) + rminfo.bufmem * pgsize;
  745.         plist = AddElem(plist, "FS Cache", "FS Cache", IRIX, mem, mem,
  746.                 0, 0, i++, 0);
  747.         kmem -= rminfo.bufmem * pgsize;
  748.  
  749.         /*
  750.          * Subtract streams from heap, since streams memory is
  751.          * part of the heap
  752.          */
  753.         mem = minfo.heapmem / 1024 - rminfo.strmem * pgsize;
  754.         plist = AddElem(plist, "Heap", "Heap", IRIX,
  755.                 mem, mem, 0, 0, i++, 0);
  756.         kmem -= mem;
  757.  
  758.         mem = rminfo.strmem * pgsize;
  759.         plist = AddElem(plist, "Streams", "Streams", IRIX,
  760.                 mem, mem, 0, 0, i++, 0);
  761.         kmem -= mem;
  762.  
  763.         mem = minfo.zonemem / 1024;
  764.         plist = AddElem(plist, "Zone", "Zone", IRIX,
  765.                 mem, mem, 0, 0, i++, 0);
  766.         kmem -= mem;
  767.  
  768.         mem = minfo.bsdnet / 1024;
  769.         plist = AddElem(plist, "BSD Networking",
  770.                 "BSD Networking", IRIX,
  771.                 mem, mem, 0, 0, i++, 0);
  772.         kmem -= mem;
  773.  
  774.         mem = ketext - kpstart;        /* Kernel Text */
  775.         mem += kend - ketext;        /* Kernel Data */
  776.         if (kpbase > kend) {
  777.         mem += kpbase - kpfdat;        /* Page Frames */
  778.         mem += kpfdat - kend;        /* Kernel Tables */
  779.         }
  780.         mem /= 1024;
  781.         kmem -= mem;
  782.         plist = AddElem(plist, "Other", "Other", IRIX,
  783.                 kmem, kmem, 0, 0, i++, 0);
  784.  
  785.         if (kpbase > kend) {
  786.         mem = (kpbase - kpfdat) / 1024;
  787.         plist = AddElem(plist, "Page Frame Data", "Page Frame Data",
  788.                 IRIX, mem, mem, 0, 0, i++, 0);
  789.         mem = (kpfdat - kend) / 1024;
  790.         plist = AddElem(plist, "Kernel Tables", "Kernel Tables",
  791.                 IRIX, mem, mem, 0, 0, i++, 0);
  792.         }
  793.         mem = (kend - ketext) / 1024;
  794.         plist = AddElem(plist, "Unix Data Space", "Unix Data Space",
  795.                 IRIX, mem, mem, 0, 0, i++, 0);
  796.         if ((ktext - kpstart) > 2*NBPP) {
  797.         mem = (ketext - ktext) / 1024;
  798.         plist = AddElem(plist, "Unix Code Space", "Unix Code Space",
  799.                 IRIX, mem, mem, 0, 0, i++, 0);
  800.         mem = (ktext - kpstart) / 1024;
  801.         plist = AddElem(plist, "Symmon", "Symmon", IRIX,
  802.                 mem, mem, 0, 0, i++, 0);
  803.         } else {
  804.         mem = (ketext - kpstart) / 1024;
  805.         plist = AddElem(plist, "Unix Code Space", "Unix Code Space",
  806.                 IRIX, mem, mem, 0, 0, i++, 0);
  807.         }
  808.     }
  809.     }
  810.     *all = list;
  811.     *proc = plist;
  812. }
  813.  
  814. /*
  815.  *  void
  816.  *  FreeUsage(PROGRAM *usage)
  817.  *
  818.  *  Description:
  819.  *      Free all the memory used by a usage list.
  820.  *
  821.  *  Parameters:
  822.  *      usage
  823.  */
  824.  
  825. void
  826. FreeUsage(PROGRAM *usage)
  827. {
  828.     PROGRAM *next;
  829.     
  830.     while (usage) {
  831.     next = usage->next;
  832.     free(usage->progName);
  833.     if (usage->mapName) {
  834.         free(usage->mapName);
  835.     }
  836.     free(usage);
  837.     usage = next;
  838.     }
  839. }
  840.